/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.community.component.spreadsheet.asset;

import cn.ac.nercis.pes.common.constant.common.AssetConstants;
import cn.ac.nercis.pes.common.constant.evaluation.AssetImportance;
import cn.ac.nercis.pes.common.constant.evaluation.EvaluationTag;
import cn.ac.nercis.pes.community.component.spreadsheet.TableSheetView;
import cn.ac.nercis.pes.community.model.vo.asset.PhySecurityVO;
import cn.ac.nercis.pes.community.support.event.EventCallback;
import cn.ac.nercis.pes.model.dto.common.ItemData;
import cn.ac.nercis.pes.model.dto.evaluation.asset.PhyEnvDTO;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.controlsfx.control.spreadsheet.GridBase;
import org.controlsfx.control.spreadsheet.SpreadsheetCell;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 物理安防设施表控件
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
public class AssetPhySecuritySheetView extends TableSheetView<PhySecurityVO> {

    private final static List<String> COLUMNS = List.of("产品名称","生产厂商和型号","所在物理环境名称","安全需求","重要程度","是否测评","备注");
    private final static Integer NAME_COLUMN_INDEX = 0;
    private final static Integer VENDOR_COLUMN_INDEX = 1;
    private final static Integer LOCATION_COLUMN_INDEX = 2;
    private final static Integer REQ_COLUMN_INDEX = 3;
    private final static Integer IMPORTANCE_COLUMN_INDEX = 4;
    private final static Integer IS_USE_COLUMN_INDEX = 5;
    private final static Integer DESC_COLUMN_INDEX = 6;
    private final ObservableList<ItemData> locationList;
    private final ObservableList<String> reqList;
    private final ObservableList<String> importanceList;
    private final ObservableList<String> useList;
    private EventCallback<Set<String>> onDeleteAction;
    private String systemId;

    public AssetPhySecuritySheetView(){
        this.getStyleClass().add("pes-sheet-view");
        importanceList = FXCollections.observableArrayList(AssetImportance.getImportance());
        useList = FXCollections.observableArrayList(EvaluationTag.findTags());
        locationList = FXCollections.observableArrayList();
        reqList = FXCollections.observableArrayList();

        var grid = new GridBase(DEFAULT_EMPTY_DATA_COUNT, COLUMNS.size());
        grid.getColumnHeaders().addAll(COLUMNS);
        buildGrid(grid,DEFAULT_EMPTY_DATA_COUNT);
        setGrid(grid);
        getColumns().get(NAME_COLUMN_INDEX).setPrefWidth(150);
        getColumns().get(VENDOR_COLUMN_INDEX).setPrefWidth(200);
        getColumns().get(LOCATION_COLUMN_INDEX).setPrefWidth(180);
        getColumns().get(REQ_COLUMN_INDEX).setPrefWidth(180);
        getColumns().get(IMPORTANCE_COLUMN_INDEX).setPrefWidth(120);
        getColumns().get(IS_USE_COLUMN_INDEX).setPrefWidth(120);
        getColumns().get(DESC_COLUMN_INDEX).setPrefWidth(300);
        //this.setRequiredColumns();
    }

    public void initialize(String systemId,EventCallback<Set<String>> deleteAction){
        this.systemId = systemId;
        this.onDeleteAction = deleteAction;
        this.editModel.set(false);
    }

    public void refreshLocationData(List<PhyEnvDTO> locationData){
        this.locationList.clear();
        this.locationList.addAll(locationData.stream().map(item->new ItemData(item.getName(),item.getId())).toList());
    }

    public void refreshReqData(List<String> reqData){
        this.reqList.clear();
        this.reqList.addAll(reqData);
    }

    @Override
    protected void loadContent(PhySecurityVO info,Integer sheetRowIndex){
        this.checkAndAppendEmptyDataRow(sheetRowIndex);
        this.getGrid().getRows().get(sheetRowIndex).get(NAME_COLUMN_INDEX).setItem(info.getName());
        this.getGrid().getRows().get(sheetRowIndex).get(VENDOR_COLUMN_INDEX).setItem(info.getVendor());
        this.getGrid().getRows().get(sheetRowIndex).get(LOCATION_COLUMN_INDEX).setItem(info.getLocation());
        this.getGrid().getRows().get(sheetRowIndex).get(REQ_COLUMN_INDEX).setItem(info.getRequire());
        this.getGrid().getRows().get(sheetRowIndex).get(IMPORTANCE_COLUMN_INDEX).setItem(info.getImportance());
        this.getGrid().getRows().get(sheetRowIndex).get(IS_USE_COLUMN_INDEX).setItem(info.getIsUse());
        this.getGrid().getRows().get(sheetRowIndex).get(DESC_COLUMN_INDEX).setItem(info.getDesc());
        if(StringUtils.isNotBlank(info.getLocation())
                && locationList.stream().noneMatch(i->StringUtils.equals(i.getValue(),info.getQuoteAssetId()))){
            this.getGrid().getRows().get(sheetRowIndex).get(LOCATION_COLUMN_INDEX).getStyleClass().add(REQUIRED_CELL_STYLE);
        }else{
            this.getGrid().getRows().get(sheetRowIndex).get(LOCATION_COLUMN_INDEX).getStyleClass().remove(REQUIRED_CELL_STYLE);
        }
        info.resetChange();
    }

    public List<PhySecurityVO> getModifyData(){
        List<PhySecurityVO> data = new ArrayList<>();
        for(var sheetRowIndex=0;sheetRowIndex<this.getGrid().getRows().size();sheetRowIndex++){
            if(this.isEmptyData(sheetRowIndex)){
                continue;
            }
            data.add(getModifyData(sheetRowIndex));
        }
        return data.stream()
                .filter(item-> Objects.nonNull(item) && item.isChange())
                .collect(Collectors.toList());
    }

    private PhySecurityVO getModifyData(Integer sheetRowIndex){
        if (toDataIndex(sheetRowIndex) < 0) {
            return null;
        }
        var rowData = this.getGrid().getRows().get(sheetRowIndex);
        PhySecurityVO info;
        if (toDataIndex(sheetRowIndex) < this.sheetData.size()) {
            info = this.sheetData.get(toDataIndex(sheetRowIndex));
        } else {
            info = new PhySecurityVO();
        }
        info.setName(StringUtils.trim(rowData.get(NAME_COLUMN_INDEX).getText()));
        info.setVendor(StringUtils.trim(rowData.get(VENDOR_COLUMN_INDEX).getText()));
        info.setRequire(StringUtils.trim(rowData.get(REQ_COLUMN_INDEX).getText()));
        info.setImportance(StringUtils.trim(rowData.get(IMPORTANCE_COLUMN_INDEX).getText()));
        info.setDesc(StringUtils.trim(rowData.get(DESC_COLUMN_INDEX).getText()));
        info.setIsUse(StringUtils.trim(rowData.get(IS_USE_COLUMN_INDEX).getText()));
        if (StringUtils.isBlank(rowData.get(IS_USE_COLUMN_INDEX).getText())) {
            info.setIsUse(StringUtils.trim(AssetConstants.USE_TAG));
        }
        info.setLocation(StringUtils.trim(rowData.get(LOCATION_COLUMN_INDEX).getText()));
        var quoteAssetId = this.locationList.stream()
                .filter(item -> StringUtils.equals(item.getName(), info.getLocation()))
                .map(ItemData::getValue)
                .findFirst()
                .orElse("");
        info.setQuoteAssetId(StringUtils.trim(quoteAssetId));
        return info;
    }

    @Override
    protected boolean validate(ObservableList<SpreadsheetCell> rowData){
        boolean validResult = true;
        if(StringUtils.isBlank(rowData.get(NAME_COLUMN_INDEX).getText())){
            rowData.get(NAME_COLUMN_INDEX).getStyleClass().add(REQUIRED_CELL_STYLE);
            validResult = false;
        }else{
            rowData.get(NAME_COLUMN_INDEX).getStyleClass().remove(REQUIRED_CELL_STYLE);
        }
        return validResult;
    }

    @Override
    protected void clearValidate(ObservableList<SpreadsheetCell> rowData) {
        rowData.get(NAME_COLUMN_INDEX).getStyleClass().remove(REQUIRED_CELL_STYLE);
    }
    @Override
    protected boolean isEmptyData(Integer sheetRowIndex){
        if(toDataIndex(sheetRowIndex) < 0){
            return true;
        } else if(toDataIndex(sheetRowIndex) < this.sheetData.size()){
            return false;
        }
        var rowData = this.getGrid().getRows().get(sheetRowIndex);
        return StringUtils.isBlank(rowData.get(NAME_COLUMN_INDEX).getText())
                && StringUtils.isBlank(rowData.get(VENDOR_COLUMN_INDEX).getText())
                && StringUtils.isBlank(rowData.get(LOCATION_COLUMN_INDEX).getText())
                && StringUtils.isBlank(rowData.get(REQ_COLUMN_INDEX).getText())
                && StringUtils.isBlank(rowData.get(IMPORTANCE_COLUMN_INDEX).getText())
                && StringUtils.isBlank(rowData.get(IS_USE_COLUMN_INDEX).getText())
                && StringUtils.isBlank(rowData.get(DESC_COLUMN_INDEX).getText());
    }

    @Override
    protected ObservableList<SpreadsheetCell> generateEmptyDataRow(int dataIndex) {
        final ObservableList<SpreadsheetCell> data = FXCollections.observableArrayList();
        AtomicInteger columnIndex = new AtomicInteger(0);
        data.add(getTextFieldCell(toSheetRowIndex(dataIndex),columnIndex.getAndIncrement()));
        data.add(getTextAreaCell(toSheetRowIndex(dataIndex),columnIndex.getAndIncrement()));
        data.add(getComboBoxCell(toSheetRowIndex(dataIndex),columnIndex.getAndIncrement(),locationList));
        data.add(getCheckComboBoxCell(toSheetRowIndex(dataIndex),columnIndex.getAndIncrement(),
                reqList,AssetConstants.KEY_DATA_REQ_SPLIT));
        data.add(getComboBoxCell(toSheetRowIndex(dataIndex),columnIndex.getAndIncrement(),importanceList));
        data.add(getComboBoxCell(toSheetRowIndex(dataIndex),columnIndex.getAndIncrement(),useList));
        data.add(getTextAreaCell(toSheetRowIndex(dataIndex),columnIndex.getAndIncrement(),"data-cell-left"));
        return data;
    }

    @Override
    protected void deleteData() {
        if(Objects.nonNull(this.onDeleteAction)){
            var selectIds= this.selectedSheetRowIndex()
                    .stream()
                    .filter(sheetRowIndex->toDataIndex(sheetRowIndex)>=0 && toDataIndex(sheetRowIndex)<this.sheetData.size())
                    .map(sheetRowIndex->this.sheetData.get(toDataIndex(sheetRowIndex)).getId())
                    .collect(Collectors.toSet());
            this.onDeleteAction.action(selectIds);
        }
    }

    @Override
    protected List<String> getDataColumns() {
        return COLUMNS;
    }

    private void setRequiredColumns(){
        this.setCornerTag(this.getGrid().getRows().get(0).get(NAME_COLUMN_INDEX));
    }
}